#include "windows.h"
#include "tchar.h"

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) 
{
    TOKEN_PRIVILEGES tp;
    HANDLE hToken;
    LUID luid;
                                                       //GetCurrentProcess这个WinAPI函数来获得当前进程的一个伪句柄
    if( !OpenProcessToken(GetCurrentProcess(),          //打开与进程相关联的访问令牌。
                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
			              &hToken) )
    {
        _tprintf(L"OpenProcessToken error: %u\n", GetLastError());
        return FALSE;
    }
//查看系统权限的特权值，返回信息到一个LUID结构体里
    if( !LookupPrivilegeValue(NULL,           // lookup privilege on local system  所要查看的系统，本地系统直接用NULL
                              lpszPrivilege,  // privilege to lookup 指定特权的名称
                              &luid) )        // receives LUID of privilege          
    {
        _tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError() ); 
        return FALSE; 
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if( bEnablePrivilege )                   //根据参数的传入true或者是false表示是提权还是关闭sedbug
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.  启用或者进知指定令牌的特权
    if( !AdjustTokenPrivileges(hToken,   //进程句柄
                               FALSE,   //禁用所有权限的
                               &tp,     //新权限结构体
                               sizeof(TOKEN_PRIVILEGES),   //缓冲区大小
                               (PTOKEN_PRIVILEGES) NULL, 
                               (PDWORD) NULL) )
    { 
        _tprintf(L"AdjustTokenPrivileges error: %u\n", GetLastError() ); 
        return FALSE; 
    } 

    if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
    {
        _tprintf(L"The token does not have the specified privilege. \n");
        return FALSE;
    } 

    return TRUE;
}

BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
    HANDLE hProcess = NULL, hThread = NULL;
    HMODULE hMod = NULL;
    LPVOID pRemoteBuf = NULL;
    DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
    LPTHREAD_START_ROUTINE pThreadProc;


    if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )        //返回一个正在运行的进程，第一个参数是渴望得到的权限，dwPID是希望注入的进程号
    {
        _tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());
        return FALSE;
    }

    pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);  //远程进程地址空间中为注入的数据分配内存
                             //第一个参数进程句柄    //第二个参数是addr，这个一般由NULL是自动分配  第三个参数是内存大小  第四个参数为特定的页面区域分配内存中或磁盘的页面文件中的物理存储  
                            //最后一个参数是可读可写
    
    WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);//写入某一进程的内存区域
                        //pRemoteBuf是上述分配的空间地址    szDllPath是dll文件地址     

    
    hMod = GetModuleHandle(L"kernel32.dll");   //返回kernel32.dll的句柄
    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");  //从kernel.32中找到LoadLibraryW的地址
	
 
    hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);  //在指定的进程中运行一个线程，线程的地址就是LoadLibararyw
                                                                                        //，pRemoteBuf是LoadLibararyw的参数
    WaitForSingleObject(hThread, INFINITE);	

    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

int _tmain(int argc, TCHAR *argv[])
{
    if( argc != 3)
    {
        _tprintf(L"USAGE : %s <pid> <dll_path>\n", argv[0]);
        return 1;
    }
    //需要访问当前计算机上其他进程的内存的应用程序。显然，这需要管理员权限。它也需要SeDebugPrivilege
    // change privilege   提升权限
    if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )    
        return 1;

    // inject dll
    if( InjectDll((DWORD)_tstol(argv[1]), argv[2]) )   //第一个参数为进程号、第二个参数为dll文件
        _tprintf(L"InjectDll(\"%s\") success!!!\n", argv[2]);
    else
        _tprintf(L"InjectDll(\"%s\") failed!!!\n", argv[2]);

    return 0;
}